{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "cf98468b-6a08-4f1c-b5e9-1e10218dab25",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T16:05:04.489387Z",
     "iopub.status.busy": "2024-04-19T16:05:04.489185Z",
     "iopub.status.idle": "2024-04-19T16:05:04.941117Z",
     "shell.execute_reply": "2024-04-19T16:05:04.940827Z",
     "shell.execute_reply.started": "2024-04-19T16:05:04.489363Z"
    }
   },
   "outputs": [],
   "source": [
    "import json\n",
    "from web3 import Web3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "d1c7e7f4-9fda-4dcd-a8ef-67fb8c592627",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T16:05:04.942268Z",
     "iopub.status.busy": "2024-04-19T16:05:04.942099Z",
     "iopub.status.idle": "2024-04-19T16:05:15.154543Z",
     "shell.execute_reply": "2024-04-19T16:05:15.153529Z",
     "shell.execute_reply.started": "2024-04-19T16:05:04.942257Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "w3 = Web3(Web3.HTTPProvider(\"https://sepolia.infura.io/v3/824256f39eb744afb721dddb03a36600\"))\n",
    "w3.is_connected()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d8de635b-13ce-40c1-835b-8ac44e0842b3",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T11:03:44.579935Z",
     "iopub.status.busy": "2024-04-19T11:03:44.578924Z",
     "iopub.status.idle": "2024-04-19T11:03:44.585347Z",
     "shell.execute_reply": "2024-04-19T11:03:44.584488Z",
     "shell.execute_reply.started": "2024-04-19T11:03:44.579889Z"
    }
   },
   "source": [
    "# Multicall3\n",
    "\n",
    "https://github.com/mds1/multicall\n",
    "\n",
    "Deploed at `0xcA11bde05977b3631167028862bE2a173976CA11`\n",
    "\n",
    "Abi published in Sepolia / Mainnet and so on\n",
    "\n",
    "I.e. for Sepolia: https://sepolia.etherscan.io/address/0xcA11bde05977b3631167028862bE2a173976CA11#code"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "f094f80a-caff-426c-8234-d0fc734dd514",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T16:05:15.157016Z",
     "iopub.status.busy": "2024-04-19T16:05:15.156101Z",
     "iopub.status.idle": "2024-04-19T16:05:15.164858Z",
     "shell.execute_reply": "2024-04-19T16:05:15.164121Z",
     "shell.execute_reply.started": "2024-04-19T16:05:15.156976Z"
    }
   },
   "outputs": [],
   "source": [
    "MULTICALL3 = '0xcA11bde05977b3631167028862bE2a173976CA11'\n",
    "multicall3_abi = json.load(open(\"./abis/multicall3.abis\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "db341dfa-59f4-4637-9e86-bc30cebd07f0",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T16:05:15.166257Z",
     "iopub.status.busy": "2024-04-19T16:05:15.165994Z",
     "iopub.status.idle": "2024-04-19T16:05:15.191704Z",
     "shell.execute_reply": "2024-04-19T16:05:15.191156Z",
     "shell.execute_reply.started": "2024-04-19T16:05:15.166234Z"
    }
   },
   "outputs": [],
   "source": [
    "multicall_contract = w3.eth.contract(address=MULTICALL3, abi=multicall3_abi)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2ef9c0fc-c238-48bf-8c77-87df26e30662",
   "metadata": {},
   "source": [
    "**Important note:**\n",
    "\n",
    "This lib has additional helpers that implement regular RPC api calls as a contract calls to use them to wrap in multicall\n",
    "\n",
    "There are a number of other methods to return block properties, including:\n",
    "\n",
    "    getBlockHash: Returns the block hash for the given block number.\n",
    "    getBlockNumber: Returns the current block's number.\n",
    "    getCurrentBlockCoinbase: Returns the current block's coinbase.\n",
    "    getCurrentBlockDifficulty: Returns the current block's difficulty for Proof-of-Work chains or the latest RANDAO value for Proof-of-Stake chains. See EIP-4399 to learn more about this.\n",
    "    getCurrentBlockGasLimit: Returns the current block's gas limit.\n",
    "    getCurrentBlockTimestamp: Returns the current block's timestamp.\n",
    "    getEthBalance: Returns the ETH (or native token) balance of the given address.\n",
    "    getLastBlockHash: Returns the block hash of the previous block.\n",
    "    getBasefee: Returns the base fee of the given block. This will revert if the BASEFEE opcode is not supported on the given chain. See EIP-1599 to learn more about this.\n",
    "    getChainId: Returns the chain ID.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "92c85381-18d6-4e35-9051-406e80309c77",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T16:05:15.192621Z",
     "iopub.status.busy": "2024-04-19T16:05:15.192438Z",
     "iopub.status.idle": "2024-04-19T16:05:15.198246Z",
     "shell.execute_reply": "2024-04-19T16:05:15.197498Z",
     "shell.execute_reply.started": "2024-04-19T16:05:15.192603Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['abi',\n",
       " 'w3',\n",
       " 'address',\n",
       " 'aggregate',\n",
       " 'aggregate3',\n",
       " 'aggregate3Value',\n",
       " 'blockAndAggregate',\n",
       " 'getBasefee',\n",
       " 'getBlockHash',\n",
       " 'getBlockNumber',\n",
       " 'getChainId',\n",
       " 'getCurrentBlockCoinbase',\n",
       " 'getCurrentBlockDifficulty',\n",
       " 'getCurrentBlockGasLimit',\n",
       " 'getCurrentBlockTimestamp',\n",
       " 'getEthBalance',\n",
       " 'getLastBlockHash',\n",
       " 'tryAggregate',\n",
       " 'tryBlockAndAggregate']"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Get a list of SC functions (w/o python helpers)\n",
    "[i for i in multicall_contract.functions.__dir__() if not i.startswith('_')]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b37b6453-a123-48fd-a6fc-3bfc29afd7dd",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T11:16:30.298538Z",
     "iopub.status.busy": "2024-04-19T11:16:30.298141Z",
     "iopub.status.idle": "2024-04-19T11:16:30.301878Z",
     "shell.execute_reply": "2024-04-19T11:16:30.301068Z",
     "shell.execute_reply.started": "2024-04-19T11:16:30.298512Z"
    }
   },
   "source": [
    "# Multiple Eth balance fetching"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "25fa17e0-3a04-4ce5-a797-9bfe2cbe0c62",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T16:05:15.199022Z",
     "iopub.status.busy": "2024-04-19T16:05:15.198879Z",
     "iopub.status.idle": "2024-04-19T16:05:15.202189Z",
     "shell.execute_reply": "2024-04-19T16:05:15.201544Z",
     "shell.execute_reply.started": "2024-04-19T16:05:15.199007Z"
    }
   },
   "outputs": [],
   "source": [
    "MY_ADDRESS = '0x997d4c6A7cA5d524babDf1b205351f6FB623b5E7'\n",
    "# Top accounts from https://sepolia.etherscan.io/accounts\n",
    "TOP_ACCOUNT1 = '0x25c4a76E7d118705e7Ea2e9b7d8C59930d8aCD3b'\n",
    "TOP_ACCOUNT2 = '0xd7d76c58b3a519e9fA6Cc4D22dC017259BC49F1E'"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "83cedda4-f8fc-42cc-a550-3cfe7cf9e13b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T13:14:32.783944Z",
     "iopub.status.busy": "2024-04-19T13:14:32.783562Z",
     "iopub.status.idle": "2024-04-19T13:14:32.787665Z",
     "shell.execute_reply": "2024-04-19T13:14:32.786698Z",
     "shell.execute_reply.started": "2024-04-19T13:14:32.783919Z"
    }
   },
   "source": [
    "## Sequential request of balances via RPC"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "fead2a49-26fb-4927-ab6a-0f73b8b6243b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T16:05:15.205682Z",
     "iopub.status.busy": "2024-04-19T16:05:15.205438Z",
     "iopub.status.idle": "2024-04-19T16:05:16.937821Z",
     "shell.execute_reply": "2024-04-19T16:05:16.936959Z",
     "shell.execute_reply.started": "2024-04-19T16:05:15.205666Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('6.031617160292639647',\n",
       " '100000480.489788483671356374',\n",
       " '100000000.00107',\n",
       " '6.031617160292639647',\n",
       " '100000480.489788483671356374',\n",
       " '100000000.00107')"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Sequential get accounts balances\n",
    "(\n",
    "    str(w3.from_wei(w3.eth.get_balance(MY_ADDRESS), unit='ether')),\n",
    "    str(w3.from_wei(w3.eth.get_balance(TOP_ACCOUNT1), unit='ether')),\n",
    "    str(w3.from_wei(w3.eth.get_balance(TOP_ACCOUNT2), unit='ether')),\n",
    "    str(w3.from_wei(w3.eth.get_balance(MY_ADDRESS), unit='ether')),\n",
    "    str(w3.from_wei(w3.eth.get_balance(TOP_ACCOUNT1), unit='ether')),\n",
    "    str(w3.from_wei(w3.eth.get_balance(TOP_ACCOUNT2), unit='ether')),\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "34b45392-b33a-45c1-8c08-351c5a515006",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T16:05:16.939323Z",
     "iopub.status.busy": "2024-04-19T16:05:16.939069Z",
     "iopub.status.idle": "2024-04-19T16:05:25.834209Z",
     "shell.execute_reply": "2024-04-19T16:05:25.833046Z",
     "shell.execute_reply.started": "2024-04-19T16:05:16.939298Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1.11 s ± 31.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
     ]
    }
   ],
   "source": [
    "%%timeit\n",
    "(\n",
    "    str(w3.from_wei(w3.eth.get_balance(MY_ADDRESS), unit='ether')),\n",
    "    str(w3.from_wei(w3.eth.get_balance(TOP_ACCOUNT1), unit='ether')),\n",
    "    str(w3.from_wei(w3.eth.get_balance(TOP_ACCOUNT2), unit='ether')),\n",
    "    str(w3.from_wei(w3.eth.get_balance(MY_ADDRESS), unit='ether')),\n",
    "    str(w3.from_wei(w3.eth.get_balance(TOP_ACCOUNT1), unit='ether')),\n",
    "    str(w3.from_wei(w3.eth.get_balance(TOP_ACCOUNT2), unit='ether')),\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "27fa154a-f5ab-4873-a7bd-f4e5928b61de",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T13:16:25.408974Z",
     "iopub.status.busy": "2024-04-19T13:16:25.408614Z",
     "iopub.status.idle": "2024-04-19T13:16:25.414336Z",
     "shell.execute_reply": "2024-04-19T13:16:25.413382Z",
     "shell.execute_reply.started": "2024-04-19T13:16:25.408949Z"
    }
   },
   "source": [
    "**Note here**\n",
    "\n",
    "Above operation takes ~1.08s/1.03s/1.04s on my machine"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "0ecf6370-899c-4044-92ef-56ca9d398f9c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T16:05:25.836307Z",
     "iopub.status.busy": "2024-04-19T16:05:25.835865Z",
     "iopub.status.idle": "2024-04-19T16:05:28.020542Z",
     "shell.execute_reply": "2024-04-19T16:05:28.019598Z",
     "shell.execute_reply.started": "2024-04-19T16:05:25.836275Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('6.031617160292639647',\n",
       " '100000480.489788483671356374',\n",
       " '100000000.00107',\n",
       " '6.031617160292639647',\n",
       " '100000480.489788483671356374',\n",
       " '100000000.00107')"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Sequential get account balance via Multicall3\n",
    "(\n",
    "    str(w3.from_wei(multicall_contract.functions.getEthBalance(MY_ADDRESS).call(),unit='ether')),\n",
    "    str(w3.from_wei(multicall_contract.functions.getEthBalance(TOP_ACCOUNT1).call(),unit='ether')),\n",
    "    str(w3.from_wei(multicall_contract.functions.getEthBalance(TOP_ACCOUNT2).call(),unit='ether')),\n",
    "    str(w3.from_wei(multicall_contract.functions.getEthBalance(MY_ADDRESS).call(),unit='ether')),\n",
    "    str(w3.from_wei(multicall_contract.functions.getEthBalance(TOP_ACCOUNT1).call(),unit='ether')),\n",
    "    str(w3.from_wei(multicall_contract.functions.getEthBalance(TOP_ACCOUNT2).call(),unit='ether')),\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "2cc73765-86d3-405d-b21e-39736a194f30",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T16:05:28.022757Z",
     "iopub.status.busy": "2024-04-19T16:05:28.022321Z",
     "iopub.status.idle": "2024-04-19T16:05:45.984919Z",
     "shell.execute_reply": "2024-04-19T16:05:45.984014Z",
     "shell.execute_reply.started": "2024-04-19T16:05:28.022720Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.24 s ± 42.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
     ]
    }
   ],
   "source": [
    "%%timeit\n",
    "(\n",
    "    str(w3.from_wei(multicall_contract.functions.getEthBalance(MY_ADDRESS).call(),unit='ether')),\n",
    "    str(w3.from_wei(multicall_contract.functions.getEthBalance(TOP_ACCOUNT1).call(),unit='ether')),\n",
    "    str(w3.from_wei(multicall_contract.functions.getEthBalance(TOP_ACCOUNT2).call(),unit='ether')),\n",
    "    str(w3.from_wei(multicall_contract.functions.getEthBalance(MY_ADDRESS).call(),unit='ether')),\n",
    "    str(w3.from_wei(multicall_contract.functions.getEthBalance(TOP_ACCOUNT1).call(),unit='ether')),\n",
    "    str(w3.from_wei(multicall_contract.functions.getEthBalance(TOP_ACCOUNT2).call(),unit='ether')),\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "24da990e-b8a8-4351-856c-2cbb752cc43a",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T13:17:12.013775Z",
     "iopub.status.busy": "2024-04-19T13:17:12.013427Z",
     "iopub.status.idle": "2024-04-19T13:17:12.016928Z",
     "shell.execute_reply": "2024-04-19T13:17:12.016173Z",
     "shell.execute_reply.started": "2024-04-19T13:17:12.013751Z"
    }
   },
   "source": [
    "## Parallel getBalance via Multicall3 aggregate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "75fdf259-9369-4958-979d-3c87ccbc5306",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T16:05:45.986765Z",
     "iopub.status.busy": "2024-04-19T16:05:45.986426Z",
     "iopub.status.idle": "2024-04-19T16:05:45.995590Z",
     "shell.execute_reply": "2024-04-19T16:05:45.994897Z",
     "shell.execute_reply.started": "2024-04-19T16:05:45.986739Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('0x4d2301cc000000000000000000000000997d4c6a7ca5d524babdf1b205351f6fb623b5e7',\n",
       " '0x4d2301cc00000000000000000000000025c4a76e7d118705e7ea2e9b7d8c59930d8acd3b',\n",
       " '0x4d2301cc000000000000000000000000d7d76c58b3a519e9fa6cc4d22dc017259bc49f1e')"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# prepare function call encode data\n",
    "get_balance_of_MY_ACCOUNT_call = multicall_contract.functions.getEthBalance(MY_ADDRESS)._encode_transaction_data()\n",
    "get_balance_of_TOP_ACCOUNT1_call = multicall_contract.functions.getEthBalance(TOP_ACCOUNT1)._encode_transaction_data()\n",
    "get_balance_of_TOP_ACCOUNT2_call = multicall_contract.functions.getEthBalance(TOP_ACCOUNT2)._encode_transaction_data()\n",
    "get_balance_of_MY_ACCOUNT_call, get_balance_of_TOP_ACCOUNT1_call, get_balance_of_TOP_ACCOUNT2_call"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "34c83d21-f7fa-4987-b213-172716f56b25",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T16:05:45.996879Z",
     "iopub.status.busy": "2024-04-19T16:05:45.996569Z",
     "iopub.status.idle": "2024-04-19T16:05:46.013632Z",
     "shell.execute_reply": "2024-04-19T16:05:46.013146Z",
     "shell.execute_reply.started": "2024-04-19T16:05:45.996857Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Function aggregate((address,bytes)[]) bound to ([['0xcA11bde05977b3631167028862bE2a173976CA11', '0x4d2301cc000000000000000000000000997d4c6a7ca5d524babdf1b205351f6fb623b5e7'], ['0xcA11bde05977b3631167028862bE2a173976CA11', '0x4d2301cc00000000000000000000000025c4a76e7d118705e7ea2e9b7d8c59930d8acd3b'], ['0xcA11bde05977b3631167028862bE2a173976CA11', '0x4d2301cc000000000000000000000000d7d76c58b3a519e9fa6cc4d22dc017259bc49f1e'], ['0xcA11bde05977b3631167028862bE2a173976CA11', '0x4d2301cc000000000000000000000000997d4c6a7ca5d524babdf1b205351f6fb623b5e7'], ['0xcA11bde05977b3631167028862bE2a173976CA11', '0x4d2301cc00000000000000000000000025c4a76e7d118705e7ea2e9b7d8c59930d8acd3b'], ['0xcA11bde05977b3631167028862bE2a173976CA11', '0x4d2301cc000000000000000000000000d7d76c58b3a519e9fa6cc4d22dc017259bc49f1e']],)>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "'0x252dba420000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000ca11bde05977b3631167028862be2a173976ca11000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000244d2301cc000000000000000000000000997d4c6a7ca5d524babdf1b205351f6fb623b5e700000000000000000000000000000000000000000000000000000000000000000000000000000000ca11bde05977b3631167028862be2a173976ca11000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000244d2301cc00000000000000000000000025c4a76e7d118705e7ea2e9b7d8c59930d8acd3b00000000000000000000000000000000000000000000000000000000000000000000000000000000ca11bde05977b3631167028862be2a173976ca11000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000244d2301cc000000000000000000000000d7d76c58b3a519e9fa6cc4d22dc017259bc49f1e00000000000000000000000000000000000000000000000000000000000000000000000000000000ca11bde05977b3631167028862be2a173976ca11000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000244d2301cc000000000000000000000000997d4c6a7ca5d524babdf1b205351f6fb623b5e700000000000000000000000000000000000000000000000000000000000000000000000000000000ca11bde05977b3631167028862be2a173976ca11000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000244d2301cc00000000000000000000000025c4a76e7d118705e7ea2e9b7d8c59930d8acd3b00000000000000000000000000000000000000000000000000000000000000000000000000000000ca11bde05977b3631167028862be2a173976ca11000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000244d2301cc000000000000000000000000d7d76c58b3a519e9fa6cc4d22dc017259bc49f1e00000000000000000000000000000000000000000000000000000000'"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# prepare function call of aggregate with a list encoded function call data \n",
    "multicall_call = multicall_contract.functions.aggregate([\n",
    "    [MULTICALL3, get_balance_of_MY_ACCOUNT_call],\n",
    "    [MULTICALL3, get_balance_of_TOP_ACCOUNT1_call],\n",
    "    [MULTICALL3, get_balance_of_TOP_ACCOUNT2_call],\n",
    "    [MULTICALL3, get_balance_of_MY_ACCOUNT_call],\n",
    "    [MULTICALL3, get_balance_of_TOP_ACCOUNT1_call],\n",
    "    [MULTICALL3, get_balance_of_TOP_ACCOUNT2_call],\n",
    "])\n",
    "display(multicall_call)\n",
    "multicall_call._encode_transaction_data()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "18b85795-130c-4296-b1c4-3eca7be01fff",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T16:05:46.014555Z",
     "iopub.status.busy": "2024-04-19T16:05:46.014293Z",
     "iopub.status.idle": "2024-04-19T16:05:46.381271Z",
     "shell.execute_reply": "2024-04-19T16:05:46.379951Z",
     "shell.execute_reply.started": "2024-04-19T16:05:46.014538Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[5732710,\n",
       " [b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00S\\xb4\\x9b\\xd9\\xb4d\\xa3\\x9f',\n",
       "  b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00R\\xb7\\xec\\xe8\\xea\\xb1\\xb4\\xa7\\xce\\xf3\\xd6',\n",
       "  b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00R\\xb7\\xd2\\xdc\\xcb\\xd9\\xfb\\xad\\xe8\\xe0\\x00',\n",
       "  b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00S\\xb4\\x9b\\xd9\\xb4d\\xa3\\x9f',\n",
       "  b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00R\\xb7\\xec\\xe8\\xea\\xb1\\xb4\\xa7\\xce\\xf3\\xd6',\n",
       "  b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00R\\xb7\\xd2\\xdc\\xcb\\xd9\\xfb\\xad\\xe8\\xe0\\x00']]"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Parallel call to multiple ETH balances\n",
    "result = multicall_call.call()\n",
    "result\n",
    "# First element it is block number\n",
    "# Second element it is an array of results\n",
    "# Results are array of bytes and you need to know how to interpret this values"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "7733322e-e440-4597-aa87-e3e5b920dfd3",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T16:05:46.382752Z",
     "iopub.status.busy": "2024-04-19T16:05:46.382524Z",
     "iopub.status.idle": "2024-04-19T16:05:49.530722Z",
     "shell.execute_reply": "2024-04-19T16:05:49.529477Z",
     "shell.execute_reply.started": "2024-04-19T16:05:46.382730Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "394 ms ± 27.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
     ]
    }
   ],
   "source": [
    "%%timeit\n",
    "result = multicall_call.call()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4af80607-adc6-49a9-860f-ee93866ecf83",
   "metadata": {},
   "source": [
    "**(!!!) Note here**\n",
    "\n",
    "Above call executed in ~357/350/349ms on my machine, that is way faster sequential request of balances\n",
    "\n",
    "Because aggregate is a single request to RPC api not a 6 different requests"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6a05ab52-994a-401b-a246-d7e170fb60c4",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T11:43:21.628559Z",
     "iopub.status.busy": "2024-04-19T11:43:21.628182Z",
     "iopub.status.idle": "2024-04-19T11:43:21.634279Z",
     "shell.execute_reply": "2024-04-19T11:43:21.631814Z",
     "shell.execute_reply.started": "2024-04-19T11:43:21.628534Z"
    }
   },
   "source": [
    "# Interprets a results"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "3412d632-1d2f-4bcd-aacd-fa827ecb4740",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T16:05:49.532830Z",
     "iopub.status.busy": "2024-04-19T16:05:49.532424Z",
     "iopub.status.idle": "2024-04-19T16:05:49.537870Z",
     "shell.execute_reply": "2024-04-19T16:05:49.536871Z",
     "shell.execute_reply.started": "2024-04-19T16:05:49.532787Z"
    }
   },
   "outputs": [],
   "source": [
    "from eth_abi import decode"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "8007dc61-94c9-4bbe-bbfc-0126eee999bf",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T16:05:49.539485Z",
     "iopub.status.busy": "2024-04-19T16:05:49.539252Z",
     "iopub.status.idle": "2024-04-19T16:05:49.544487Z",
     "shell.execute_reply": "2024-04-19T16:05:49.543884Z",
     "shell.execute_reply.started": "2024-04-19T16:05:49.539462Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'inputs': [{'internalType': 'address', 'name': 'addr', 'type': 'address'}],\n",
       " 'name': 'getEthBalance',\n",
       " 'outputs': [{'internalType': 'uint256',\n",
       "   'name': 'balance',\n",
       "   'type': 'uint256'}],\n",
       " 'stateMutability': 'view',\n",
       " 'type': 'function'}"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# you need to know abi of calls\n",
    "multicall_contract.functions.getEthBalance(MY_ADDRESS).abi\n",
    "# so outputs are only one param with type = uint256"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "25c2c62c-98ad-4b9a-8e87-5be196c1fe2f",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T16:05:49.545796Z",
     "iopub.status.busy": "2024-04-19T16:05:49.545495Z",
     "iopub.status.idle": "2024-04-19T16:05:49.550743Z",
     "shell.execute_reply": "2024-04-19T16:05:49.549743Z",
     "shell.execute_reply.started": "2024-04-19T16:05:49.545774Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(6031617160292639647,)\n",
      "(100000480489788483671356374,)\n",
      "(100000000001070000000000000,)\n",
      "(6031617160292639647,)\n",
      "(100000480489788483671356374,)\n",
      "(100000000001070000000000000,)\n"
     ]
    }
   ],
   "source": [
    "for i in result[1]:\n",
    "    print(decode(types=['uint256'],data=i))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "34d1073c-1e10-442d-8941-97a03f9e2259",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T16:05:49.551930Z",
     "iopub.status.busy": "2024-04-19T16:05:49.551754Z",
     "iopub.status.idle": "2024-04-19T16:05:52.445130Z",
     "shell.execute_reply": "2024-04-19T16:05:52.444414Z",
     "shell.execute_reply.started": "2024-04-19T16:05:49.551912Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "check = tuple([str(w3.from_wei(decode(types=['uint256'],data=i)[0], unit='ether'))\n",
    " for i in multicall_call.call()[1]])\n",
    "check == (\n",
    "    str(w3.from_wei(w3.eth.get_balance(MY_ADDRESS), unit='ether')),\n",
    "    str(w3.from_wei(w3.eth.get_balance(TOP_ACCOUNT1), unit='ether')),\n",
    "    str(w3.from_wei(w3.eth.get_balance(TOP_ACCOUNT2), unit='ether')),\n",
    "    str(w3.from_wei(w3.eth.get_balance(MY_ADDRESS), unit='ether')),\n",
    "    str(w3.from_wei(w3.eth.get_balance(TOP_ACCOUNT1), unit='ether')),\n",
    "    str(w3.from_wei(w3.eth.get_balance(TOP_ACCOUNT2), unit='ether')),\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eddc69b5-8788-4a09-9f94-ba3d40cb8224",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T16:02:06.648653Z",
     "iopub.status.busy": "2024-04-19T16:02:06.648264Z",
     "iopub.status.idle": "2024-04-19T16:02:06.652631Z",
     "shell.execute_reply": "2024-04-19T16:02:06.651859Z",
     "shell.execute_reply.started": "2024-04-19T16:02:06.648605Z"
    }
   },
   "source": [
    "## Call result in the past"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "4ada361c-e5f4-452b-af56-80dde1ab5d57",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T16:05:52.446784Z",
     "iopub.status.busy": "2024-04-19T16:05:52.446484Z",
     "iopub.status.idle": "2024-04-19T16:05:52.628486Z",
     "shell.execute_reply": "2024-04-19T16:05:52.627718Z",
     "shell.execute_reply.started": "2024-04-19T16:05:52.446759Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "5732711"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "w3.eth.block_number"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "e90ebfe1-e84b-4981-8636-69b808269f65",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T16:05:52.629848Z",
     "iopub.status.busy": "2024-04-19T16:05:52.629577Z",
     "iopub.status.idle": "2024-04-19T16:05:53.257285Z",
     "shell.execute_reply": "2024-04-19T16:05:53.256046Z",
     "shell.execute_reply.started": "2024-04-19T16:05:52.629826Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[5732600,\n",
       " [b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00S\\xb4\\x9b\\xd9\\xb4d\\xa3\\x9f',\n",
       "  b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00R\\xb7\\xec\\xe7\\x90A\\xc7V\\xbc=\\xd6',\n",
       "  b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00R\\xb7\\xd2\\xdc\\xcb\\xd9\\xfb\\xad\\xe8\\xe0\\x00',\n",
       "  b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00S\\xb4\\x9b\\xd9\\xb4d\\xa3\\x9f',\n",
       "  b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00R\\xb7\\xec\\xe7\\x90A\\xc7V\\xbc=\\xd6',\n",
       "  b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00R\\xb7\\xd2\\xdc\\xcb\\xd9\\xfb\\xad\\xe8\\xe0\\x00']]"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "res = multicall_call.call(block_identifier=5732600)\n",
    "res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "259aaf58-df29-4f02-b0f6-55b951361ca6",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T16:05:53.259073Z",
     "iopub.status.busy": "2024-04-19T16:05:53.258671Z",
     "iopub.status.idle": "2024-04-19T16:05:53.264380Z",
     "shell.execute_reply": "2024-04-19T16:05:53.263773Z",
     "shell.execute_reply.started": "2024-04-19T16:05:53.259047Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['6.031617160292639647',\n",
       " '100000480.392275076671356374',\n",
       " '100000000.00107',\n",
       " '6.031617160292639647',\n",
       " '100000480.392275076671356374',\n",
       " '100000000.00107']"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "[str(w3.from_wei(decode(types=['uint256'],data=i)[0], unit='ether'))\n",
    " for i in res[1]]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "7db6782b-1967-449c-b097-45dcca83321d",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T16:05:53.270698Z",
     "iopub.status.busy": "2024-04-19T16:05:53.270288Z",
     "iopub.status.idle": "2024-04-19T16:05:53.930298Z",
     "shell.execute_reply": "2024-04-19T16:05:53.928956Z",
     "shell.execute_reply.started": "2024-04-19T16:05:53.270669Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[5731600,\n",
       " [b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00S\\xb4\\x9b\\xd9\\xb4d\\xa3\\x9f',\n",
       "  b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00R\\xb7\\xec\\xdd\\x17\\xf2\\x8f\\xb1i\\xc1\\xd6',\n",
       "  b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00R\\xb7\\xd2\\xdc\\xcb\\xd9\\xfb\\xad\\xe8\\xe0\\x00',\n",
       "  b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00S\\xb4\\x9b\\xd9\\xb4d\\xa3\\x9f',\n",
       "  b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00R\\xb7\\xec\\xdd\\x17\\xf2\\x8f\\xb1i\\xc1\\xd6',\n",
       "  b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00R\\xb7\\xd2\\xdc\\xcb\\xd9\\xfb\\xad\\xe8\\xe0\\x00']]"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "res = multicall_call.call(block_identifier=5731600)\n",
    "res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "2985ec82-7432-4919-a8c9-73dae324a557",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T16:05:53.932590Z",
     "iopub.status.busy": "2024-04-19T16:05:53.932075Z",
     "iopub.status.idle": "2024-04-19T16:05:53.941407Z",
     "shell.execute_reply": "2024-04-19T16:05:53.939896Z",
     "shell.execute_reply.started": "2024-04-19T16:05:53.932555Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['6.031617160292639647',\n",
       " '100000479.637835038671356374',\n",
       " '100000000.00107',\n",
       " '6.031617160292639647',\n",
       " '100000479.637835038671356374',\n",
       " '100000000.00107']"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "[str(w3.from_wei(decode(types=['uint256'],data=i)[0], unit='ether'))\n",
    " for i in res[1]]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d8cb420e-5ec1-47b7-96ae-c69512211248",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
